package cuongnh.project.japanesediary.vocabulary.ui.dialog;

import java.util.Collections;
import java.util.Set;

import org.eclipse.core.databinding.DataBindingContext;
import org.eclipse.core.databinding.observable.set.IObservableSet;
import org.eclipse.core.databinding.property.Properties;
import org.eclipse.jface.action.Action;
import org.eclipse.jface.action.IMenuListener;
import org.eclipse.jface.action.IMenuManager;
import org.eclipse.jface.action.MenuManager;
import org.eclipse.jface.databinding.viewers.ObservableSetTreeContentProvider;
import org.eclipse.jface.dialogs.Dialog;
import org.eclipse.jface.dialogs.IDialogConstants;
import org.eclipse.jface.viewers.ISelectionChangedListener;
import org.eclipse.jface.viewers.IStructuredSelection;
import org.eclipse.jface.viewers.SelectionChangedEvent;
import org.eclipse.jface.viewers.StructuredSelection;
import org.eclipse.jface.viewers.TreeViewer;
import org.eclipse.jface.window.Window;
import org.eclipse.jface.wizard.WizardDialog;
import org.eclipse.swt.SWT;
import org.eclipse.swt.graphics.Point;
import org.eclipse.swt.layout.GridData;
import org.eclipse.swt.layout.GridLayout;
import org.eclipse.swt.widgets.Button;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Control;
import org.eclipse.swt.widgets.Event;
import org.eclipse.swt.widgets.Listener;
import org.eclipse.swt.widgets.Menu;
import org.eclipse.swt.widgets.Shell;
import org.eclipse.swt.widgets.Tree;
import org.eclipse.ui.dialogs.FilteredTree;
import org.eclipse.ui.dialogs.PatternFilter;
import org.eclipse.wb.rcp.databinding.BeansSetObservableFactory;
import org.eclipse.wb.rcp.databinding.TreeBeanAdvisor;
import org.eclipse.wb.rcp.databinding.TreeObservableLabelProvider;

import cuongnh.project.japanesediary.vocabulary.common.CommonServices;
import cuongnh.project.japanesediary.vocabulary.model.Category;
import cuongnh.project.japanesediary.vocabulary.ui.wizard.AddCategoryWizard;
import org.eclipse.swt.widgets.TreeColumn;
import org.eclipse.jface.viewers.TreeViewerColumn;

public class AddRelatedCategoryDialog extends Dialog {
	private DataBindingContext m_bindingContext;
	private TreeViewer treeViewer;
	private CommonServices commonServices;
	private Set<Category> categories;
	private Category selectedCategory;
	private Tree tree;

	/**
	 * Create the dialog.
	 * 
	 * @param parentShell
	 */
	public AddRelatedCategoryDialog(Shell parentShell,
			CommonServices commonServices) {
		super(parentShell);
		setShellStyle(SWT.MAX | SWT.RESIZE);
		this.commonServices = commonServices;
	}

	public void initData() {
		categories = (commonServices.getCategoryDao() != null) ? commonServices
				.getCategoryDao().getAllParentWithSubCategories() : Collections
				.<Category> emptySet();
		// categoriesList.setInput(categories);
	}

	/**
	 * Create contents of the dialog.
	 * 
	 * @param parent
	 */
	@Override
	protected Control createDialogArea(Composite parent) {
		Composite container = (Composite) super.createDialogArea(parent);

		PatternFilter filter = new PatternFilter();
		container.setLayout(new GridLayout(2, false));
		final FilteredTree filteredTree = new FilteredTree(container, SWT.BORDER | SWT.FULL_SELECTION | SWT.MULTI
				| SWT.H_SCROLL | SWT.V_SCROLL, filter, true);
		GridData gd_filteredTree = new GridData(SWT.FILL, SWT.FILL, true, true,
				1, 1);
		gd_filteredTree.widthHint = 496;
		filteredTree.setLayoutData(gd_filteredTree);
		treeViewer = filteredTree.getViewer();
		treeViewer.setUseHashlookup(true);
		filteredTree.getPatternFilter().setPattern("");
		filteredTree.getFilterControl().setText("");
		treeViewer.refresh();
		treeViewer.expandAll();
		tree = treeViewer.getTree();
		tree.setHeaderVisible(true);
		tree.setLinesVisible(true);
		GridData gd_tree = new GridData(SWT.FILL, SWT.FILL, true, true, 2, 1);
		gd_tree.heightHint = 338;
		gd_tree.widthHint = 278;

		initContextMenu();
		tree.setLayoutData(gd_tree);
		
		TreeViewerColumn treeViewerColumn = new TreeViewerColumn(filteredTree.getViewer(), SWT.NONE);
		TreeColumn trclmnCategory = treeViewerColumn.getColumn();
		trclmnCategory.setMoveable(true);
		trclmnCategory.setAlignment(SWT.CENTER);
		trclmnCategory.setWidth(368);
		trclmnCategory.setText("Category");

		Button btnNew = new Button(container, SWT.NONE);
		btnNew.setLayoutData(new GridData(SWT.LEFT, SWT.TOP, false, false, 1, 1));
		btnNew.setText("New...");
		btnNew.addListener(SWT.Selection, new Listener() {

			@Override
			public void handleEvent(Event event) {
				AddCategoryWizard addCategoryWizard = new AddCategoryWizard(new Category(),
						commonServices);
				WizardDialog dialog = new WizardDialog(getShell(),
						addCategoryWizard);
				if (dialog.open() == Window.OK) {
					Category newOne = addCategoryWizard.getCategory();
					if(newOne.getParentCategory() != null){
						Category parentCategory = newOne.getParentCategory();
						parentCategory.getSubCategories().add(newOne);
						m_bindingContext.updateModels();
						treeViewer.refresh(parentCategory);
					}else{
						categories.add(newOne);
						m_bindingContext.updateModels();
						treeViewer.refresh();
					}

					treeViewer.setSelection(new StructuredSelection(newOne));
				}
			}
		});

		initData();
		m_bindingContext = initDataBindings();
		// Register selection listening
		treeViewer.addSelectionChangedListener(new ISelectionChangedListener() {

			@Override
			public void selectionChanged(SelectionChangedEvent event) {
				if (event.getSelection().isEmpty()) {
					return;
				}

				if (event.getSelection() instanceof IStructuredSelection) {
					IStructuredSelection selection = (IStructuredSelection) event
							.getSelection();
					selectedCategory = (Category) selection.getFirstElement();
				}
			}
		});

		return container;
	}

	/**
	 * Create contents of the button bar.
	 * 
	 * @param parent
	 */
	@Override
	protected void createButtonsForButtonBar(Composite parent) {
		createButton(parent, IDialogConstants.OK_ID, IDialogConstants.OK_LABEL,
				true);
		createButton(parent, IDialogConstants.CANCEL_ID,
				IDialogConstants.CANCEL_LABEL, false);
	}

	/**
	 * Return the initial size of the dialog.
	 */
	@Override
	protected Point getInitialSize() {
		return new Point(443, 541);
	}

	@Override
	protected void okPressed() {
		close();
	}

	private void initContextMenu() {
		// initalize the context menu
		MenuManager menuMgr = new MenuManager();
		Menu menu = menuMgr.createContextMenu(treeViewer.getControl());
		menuMgr.addMenuListener(new IMenuListener() {

			@Override
			public void menuAboutToShow(IMenuManager manager) {
				if (treeViewer.getSelection().isEmpty()) {
					return;
				}

				if (treeViewer.getSelection() instanceof IStructuredSelection) {
					IStructuredSelection selection = (IStructuredSelection) treeViewer
							.getSelection();
					Category parentCategory = (Category) selection
							.getFirstElement();
					manager.add(new AddCategoryAction(parentCategory));
				}
			}
		});

		menuMgr.setRemoveAllWhenShown(true);
		treeViewer.getControl().setMenu(menu);
	}

	private class AddCategoryAction extends Action {
		private Category parentCategory;

		public AddCategoryAction(Category parentCategory) {
			this.setText("Add category");
			this.parentCategory = parentCategory;
		}

		@Override
		public void run() {
			super.run();
			Category newOne = new Category();
			newOne.setParentCategory(parentCategory);
			AddCategoryWizard addCategoryWizard = new AddCategoryWizard(newOne,
					commonServices);
			WizardDialog dialog = new WizardDialog(getShell(),
					addCategoryWizard);
			if (dialog.open() == Window.OK) {
				newOne = addCategoryWizard.getCategory();
				if(newOne.getParentCategory() != null){
					Category parentCategory = newOne.getParentCategory();
					parentCategory.getSubCategories().add(newOne);
					m_bindingContext.updateModels();
					treeViewer.refresh(parentCategory);
				}else{
					categories.add(newOne);
					m_bindingContext.updateModels();
					treeViewer.refresh();
				}
				
				treeViewer.setSelection(new StructuredSelection(newOne));
			}
		}

	}

	protected DataBindingContext initDataBindings() {
		DataBindingContext bindingContext = new DataBindingContext();
		//
		BeansSetObservableFactory treeObservableFactory = new BeansSetObservableFactory(
				Category.class, "subCategories");
		TreeBeanAdvisor treeAdvisor = new TreeBeanAdvisor(Category.class,
				"parentCategory", "subCategories", null);
		ObservableSetTreeContentProvider treeContentProvider = new ObservableSetTreeContentProvider(
				treeObservableFactory, treeAdvisor);
		treeViewer.setLabelProvider(new TreeObservableLabelProvider(
				treeContentProvider.getKnownElements(), Category.class,
				"categoryName", null));
		treeViewer.setContentProvider(treeContentProvider);
		//
		IObservableSet selfSet = Properties.selfSet(Category.class).observe(
				categories);
		treeViewer.setInput(selfSet);

		return bindingContext;
	}

	public Category getCategory() {
		return selectedCategory;
	}
}
